using System;
using System.Globalization;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using GeoFramework.Gps;
#if !PocketPC || DesignTime || Framework20
using System.Drawing.Drawing2D;
using System.ComponentModel;
#endif
#if PocketPC
using GeoFramework.Licensing;
#endif

namespace GeoFramework.Controls
{
	/// <summary>
	/// Represents a control used to display satellite signal strengths.
	/// </summary>
#if !PocketPC || DesignTime
	[ToolboxBitmap(typeof(SatelliteSignalBar))]
	[DefaultProperty("Satellites")]
#endif
#if Framework20
#if !PocketPC
    [ToolboxItem(true)]
#endif
    [DesignTimeVisible(true)]
#endif
	[CLSCompliant(false)]
	public sealed class SatelliteSignalBar : DoubleBufferedControl
	{
		private SatelliteCollection pSatellites = new SatelliteCollection();
		private int pGapWidth = 4;
		private Font pSignalStrengthLabelFont = new Font("Tahoma", 6.0f, FontStyle.Regular);
		private SolidBrush pSignalStrengthLabelBrush = new SolidBrush(Color.Black);
		private Font pPseudorandomNumberFont = new Font("Tahoma", 8.0f, FontStyle.Regular);
		private SolidBrush pPseudorandomNumberBrush = new SolidBrush(Color.Black);
		private bool pIsUsingRealTimeData = true;
#if PocketPC
		private SolidBrush pSatelliteFixBrush = new SolidBrush(Color.LimeGreen);
#else
		private Color pSatelliteFixColor = Color.LimeGreen;
#endif

		private Color pSatelliteNoSignalFillColor = Color.Transparent;
		private Color pSatellitePoorSignalFillColor = Color.Red;
		private Color pSatelliteModerateSignalFillColor = Color.Orange;
		private Color pSatelliteGoodSignalFillColor = Color.Green;
		private Color pSatelliteExcellentSignalFillColor = Color.LightGreen;
		private Color pSatelliteNoSignalOutlineColor = Color.Transparent;
		private Color pSatellitePoorSignalOutlineColor = Color.Black;
		private Color pSatelliteModerateSignalOutlineColor = Color.Black;
		private Color pSatelliteGoodSignalOutlineColor = Color.Black;
		private Color pSatelliteExcellentSignalOutlineColor = Color.Black;

		private ColorInterpolator pFillNone = new ColorInterpolator(Color.Transparent, Color.Red, 10);
		private ColorInterpolator pFillPoor = new ColorInterpolator(Color.Red, Color.Orange, 10);
		private ColorInterpolator pFillModerate = new ColorInterpolator(Color.Orange, Color.Green, 10);
		private ColorInterpolator pFillGood = new ColorInterpolator(Color.Green, Color.LightGreen, 10);
		private ColorInterpolator pFillExcellent = new ColorInterpolator(Color.LightGreen, Color.White, 10);
		private ColorInterpolator pOutlineNone = new ColorInterpolator(Color.Transparent, Color.Gray, 10);
		private ColorInterpolator pOutlinePoor = new ColorInterpolator(Color.Gray, Color.Gray, 10);
		private ColorInterpolator pOutlineModerate = new ColorInterpolator(Color.Gray, Color.Gray, 10);
		private ColorInterpolator pOutlineGood = new ColorInterpolator(Color.Gray, Color.Gray, 10);
		private ColorInterpolator pOutlineExcellent = new ColorInterpolator(Color.Gray, Color.LightGreen, 10);

        //// Defines a 5-pointed star shape
        //private PolarCoordinate[] StarShape = new PolarCoordinate[] {
        //    new PolarCoordinate(0, Angle.Empty),


       // private object RenderSyncLock = new object();

		public SatelliteSignalBar()
			: base("GeoFramework Multithreaded Satellite Signal Bar Control (http://www.geoframeworks.com)")
		{
#if PocketPC
            Size = new Size(100, 50);
#else
			Size = new Size(200, 100);
#endif

#if PocketPC && !Framework20 && !DesignTime
            GeoFramework.IO.Devices.CurrentSatellitesChanged += new SatelliteCollectionEventHandler(Devices_CurrentSatellitesChanged);
#endif
		}

#if !PocketPC || Framework20
        protected override void OnHandleCreated(EventArgs e)
        {
            // Subscribe to events
            try
            {
                base.OnHandleCreated(e);

                // Only hook into events if we're at run-time.  Hooking events
                // at design-time can actually cause errors in the WF Designer.
                if (LicenseManager.CurrentContext.UsageMode == LicenseUsageMode.Runtime)
                {
                    GeoFramework.IO.Devices.CurrentSatellitesChanged += new SatelliteCollectionEventHandler(Devices_CurrentSatellitesChanged);
                }
            }
            catch
            {
            }
        }

        protected override void OnHandleDestroyed(EventArgs e)
        {
            try
            {
                // Only hook into events if we're at run-time.  Hooking events
                // at design-time can actually cause errors in the WF Designer.
                if (LicenseManager.CurrentContext.UsageMode == LicenseUsageMode.Runtime)
                {
                    GeoFramework.IO.Devices.CurrentSatellitesChanged -= new SatelliteCollectionEventHandler(Devices_CurrentSatellitesChanged);
                }
            }
            catch
            {
            }
            finally
            {
                base.OnHandleDestroyed(e);
            }
        }
#endif

        protected override void Dispose(bool disposing)
        {
#if PocketPC && !Framework20 && !DesignTime
            try
            {
                // This must be successful in order for the finalizer to fire
                GeoFramework.IO.Devices.CurrentSatellitesChanged -= new SatelliteCollectionEventHandler(Devices_CurrentSatellitesChanged);
            }
            catch
            {
            }
#endif

#if PocketPC
			if (pSatelliteFixBrush != null)
			{
				try
				{
					pSatelliteFixBrush.Dispose();
				}
				catch
				{
				}
				finally
				{
					pSatelliteFixBrush = null;
				}
			}
#endif

            if (pSignalStrengthLabelFont != null)
            {
                try
                {
                    pSignalStrengthLabelFont.Dispose();
                }
                catch
                {
                }
                finally
                {
                    pSignalStrengthLabelFont = null;
                }
            }
            if (pSignalStrengthLabelBrush != null)
            {
                try
                {
                    pSignalStrengthLabelBrush.Dispose();
                }
                catch
                {
                }
                finally
                {
                    pSignalStrengthLabelBrush = null;
                }
            }
            if (pPseudorandomNumberFont != null)
            {
                try
                {
                    pPseudorandomNumberFont.Dispose();
                }
                catch 
                { 
                }
                finally
                {
                    pPseudorandomNumberFont = null;
                }
            }
            if (pPseudorandomNumberBrush != null)
            {
                try
                {
                    pPseudorandomNumberBrush.Dispose();
                }
                catch 
                {
                }
                finally
                {
                    pPseudorandomNumberBrush = null;
                }
            }

            // Move on down the line
            try
            {
                base.Dispose(disposing);
            }
            catch
            {
            }
        }

      

#if !PocketPC
		protected override Size DefaultSize
		{
			get
			{
				return new Size(200, 45);
			}
		}
#endif

#if !PocketPC || DesignTime
		[Category("Satellites")]
		[Description("Controls the satellites which are currently being viewed in the control.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		//[CLSCompliant(false)]
		public SatelliteCollection Satellites
		{
			get
			{
				return pSatellites;
			}
            set
            {
				lock (this)
				{
					if(value == null)
						pSatellites.Clear();
					else
						pSatellites = value;
				}
				Thread.Sleep(0);

                if (pSatellites != null)
                {
                    // Re-render
                    InvokePaintOffScreen();
                }
            }
		}

#if !PocketPC || DesignTime
		[Category("Appearance")]
		[Description("Controls the number of pixels in between vertical satellite signal bars.")]
		[DefaultValue(typeof(int), "4")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public int GapWidth
		{
			get
			{
				return pGapWidth;
			}
			set
			{
				if (pGapWidth == value) return;
				pGapWidth = value;
				InvokePaintOffScreen();
			}
		}

		protected override void OnInitialize()
		{
			base.OnInitialize();

#if PocketPC
#if DesignTime
			pSatellites = SatelliteCollection.Random(45);
#else
            if (pIsUsingRealTimeData)
                pSatellites.MergeWith(GeoFramework.IO.Devices.CurrentSatellites);
#endif
#else
			if(DesignMode)
				pSatellites = SatelliteCollection.Random(45);
			else if(pIsUsingRealTimeData)
				pSatellites.MergeWith(GeoFramework.IO.Devices.CurrentSatellites);
#endif
		}

		//[CLSCompliant(false)]
        protected override void OnPaintOffScreen(CancelablePaintEventArgs e)
        {
			// Sort the satellites by signal
			pSatellites.Sort(SatelliteSignalToNoiseRatioComparer.Default);

            // Decide which collection to display
            //SatelliteCollection SatellitesToRender
            SatelliteCollection SatellitesToDraw = null;
            SatelliteCollection SatellitesToRender = null;
            float BarWidth;

            try
            {


#if PocketPC
                if (LicenseManager.CurrentContext.UsageMode == LicenseUsageMode.Designtime)
                {
                    SatellitesToRender = SatelliteCollection.Random(45);
                }
                else
                {
                    if (pSatellites == null)
                        return;

                    SatellitesToRender = new SatelliteCollection();

                    lock (pSatellites.SyncRoot)
                    {
                        foreach (Satellite satellite in pSatellites)
                        {
                            // Don't draw if the satellite is stale
                            if (!satellite.IsActive)
                                continue;
                            // Add it in
                            SatellitesToRender.Add(satellite);
                        }
                    }
                    Thread.Sleep(0);
                }
#else
				if(pSatellites == null)
					return;

				SatellitesToRender = new SatelliteCollection();
			
				lock (pSatellites.SyncRoot)
				{
					foreach (Satellite satellite in pSatellites)
					{
						// Don't draw if the satellite is stale
						if (!satellite.IsActive && !DesignMode)
							continue;
						// Add it in
						SatellitesToRender.Add(satellite);
					}
				}
#endif

                // Make a fake collection if necessary
                if (SatellitesToRender.Count == 0)
                    return;

                //lock (SatellitesToRender.SyncRoot)
                //{

                //e.Graphics.DrawRectangle(Pens.Black, 0, 0, Width, Height);
                // Sort the list by PRN
                SatellitesToRender.Sort(SatelliteSignalToNoiseRatioComparer.Default);
                // Calculate the width of each bar
                float TotalWidth = (Width - pGapWidth) / SatellitesToRender.Count;
                BarWidth = TotalWidth - pGapWidth;

                SatellitesToDraw = new SatelliteCollection();

                // If if the bars are thin, see if we can exclude 0 dB satellites
                if (BarWidth < 15)
                {
                    // Display only the satellites with a > 0 dB signal
                    foreach (Satellite satellite in SatellitesToRender)
                    {
                        // Draw if the signal is > 0
                        if (!satellite.SignalToNoiseRatio.IsEmpty)
                            SatellitesToDraw.Add(satellite);
                    }
                    // If there's anything left, recalculate
                    if (SatellitesToDraw.Count == 0)
                        return;
                    // Recalculate bar/total width
                    TotalWidth = (Width - pGapWidth) / SatellitesToDraw.Count;
                    BarWidth = TotalWidth - pGapWidth;
                }
                else
                {
                    // Display only the satellites with a > 0 dB signal
                    foreach (Satellite satellite in SatellitesToRender)
                    {
                        // Draw if the signal is > 0
                        SatellitesToDraw.Add(satellite);
                    }
                }
                //}

                // Anything to do?
                if (SatellitesToDraw.Count == 0)
                    return;

                // Now draw each one
                float StartX = pGapWidth;
                float StartY = (float)(Height - e.Graphics.MeasureString("10", pPseudorandomNumberFont).Height);
                float ScaleFactor = (float)(StartY
                    - e.Graphics.MeasureString("10", pSignalStrengthLabelFont).Height) / 50.0f;

                foreach (Satellite satellite in SatellitesToDraw)
                {

                    float SatelliteY = StartY - (satellite.SignalToNoiseRatio.Value * ScaleFactor);

                    // Each icon is 30x30, so we'll translate it by half the distance
                    if (satellite.IsFixed)
                    {
                        SizeF PrnSize = e.Graphics.MeasureString(satellite.PseudorandomNumber.ToString(CultureInfo.CurrentCulture), pPseudorandomNumberFont);

#if PocketPC
                        e.Graphics.FillEllipse(pSatelliteFixBrush, (int)(StartX + (BarWidth * 0.5) - (PrnSize.Width * 0.5) - 4.0), (int)(StartY - 4), (int)(PrnSize.Width + 8), (int)(PrnSize.Height + 8));
#else
						using (SolidBrush FixBrush = new SolidBrush(Color.FromArgb(Math.Min(255, SatellitesToDraw.FixedSatellites.Count * 20), pSatelliteFixColor)))
						{
							e.Graphics.FillEllipse(FixBrush, (float)(StartX + (BarWidth * 0.5) - (PrnSize.Width * 0.5) - 4.0), StartY - 4, PrnSize.Width + 8, PrnSize.Height + 8);
						}
#endif
                    }

                    StartX += pGapWidth;
                    StartX += BarWidth;
                }

                StartX = pGapWidth;

                foreach (Satellite satellite in SatellitesToDraw)
                {
                    // If the signal is 0dB, skip it
                    if (satellite.SignalToNoiseRatio.Value == 0)
                        continue;

                    // Keep drawing the satellite
                    float SatelliteY = StartY - (Math.Min(satellite.SignalToNoiseRatio.Value, 50) * ScaleFactor);

#if PocketPC
                    // Draw a rectangle for each satellite
                    SolidBrush FillBrush = new SolidBrush(GetFillColor(satellite.SignalToNoiseRatio));
                    e.Graphics.FillRectangle(FillBrush, (int)StartX, (int)SatelliteY, (int)BarWidth, (int)(StartY - SatelliteY));
                    FillBrush.Dispose();

                    Pen FillPen = new Pen(GetOutlineColor(satellite.SignalToNoiseRatio));
                    e.Graphics.DrawRectangle(FillPen, (int)StartX, (int)SatelliteY, (int)BarWidth, (int)(StartY - SatelliteY));
                    FillPen.Dispose();
#else
                    // Get the fill color
                    Color BarColor = GetFillColor(satellite.SignalToNoiseRatio);
                    float BarHue = BarColor.GetHue();

                    // Create gradients for a glass effect
                    Color topTopColor = DoubleBufferedControl.ColorFromAhsb(255, BarHue, 0.2958f, 0.7292f);
                    Color topBottomColor = DoubleBufferedControl.ColorFromAhsb(255, BarHue, 0.5875f, 0.35f);
                    Color bottomTopColor = DoubleBufferedControl.ColorFromAhsb(255, BarHue, 0.7458f, 0.2f);
                    Color bottomBottomColor = DoubleBufferedControl.ColorFromAhsb(255, BarHue, 0.6f, 0.4042f);

					// Draw a rectangle for each satellite
                    RectangleF TopRect = new RectangleF(StartX, SatelliteY, BarWidth, Convert.ToSingle((StartY - SatelliteY) * 0.5));
                    using (Brush TopFillBrush = new LinearGradientBrush(TopRect, topTopColor, topBottomColor, LinearGradientMode.Vertical))
					{
                        e.Graphics.FillRectangle(TopFillBrush, TopRect);
					}
                    // Draw a rectangle for each satellite
                    RectangleF BottomRect = new RectangleF(StartX, SatelliteY + TopRect.Height, BarWidth, TopRect.Height);
                    using (Brush BottomFillBrush = new LinearGradientBrush(BottomRect, bottomTopColor, bottomBottomColor, LinearGradientMode.Vertical))
                    {
                        e.Graphics.FillRectangle(BottomFillBrush, BottomRect);
                    }

					using(Pen FillPen = new Pen(GetOutlineColor(satellite.SignalToNoiseRatio), 1.0f))
					{
						e.Graphics.DrawRectangle(FillPen, StartX, SatelliteY, BarWidth, StartY - SatelliteY);
					}
#endif
                    string PrnString = satellite.PseudorandomNumber.ToString(CultureInfo.CurrentCulture);
                    SizeF PrnSize = e.Graphics.MeasureString(PrnString, pPseudorandomNumberFont);
                    e.Graphics.DrawString(PrnString, pPseudorandomNumberFont,
                        pPseudorandomNumberBrush, (float)(StartX + (BarWidth * 0.5) - (PrnSize.Width * 0.5)), StartY);

                    string RenderString = satellite.SignalToNoiseRatio.ToString("0 dB", CultureInfo.CurrentCulture);
                    SizeF SignalSize = e.Graphics.MeasureString(RenderString, pSignalStrengthLabelFont);
                    if (SignalSize.Width > BarWidth)
                    {
                        RenderString = satellite.SignalToNoiseRatio.ToString("0 dB", CultureInfo.CurrentCulture).Replace(" dB", "");
                        SignalSize = e.Graphics.MeasureString(RenderString, pSignalStrengthLabelFont);
                    }
                    e.Graphics.DrawString(RenderString, pSignalStrengthLabelFont,
                        pSignalStrengthLabelBrush, (float)(StartX + (BarWidth * 0.5) - (SignalSize.Width * 0.5)), SatelliteY - SignalSize.Height);

                    StartX += pGapWidth;
                    StartX += BarWidth;
                }

            }
            catch (NullReferenceException)
            {
                // Don't throw because the control is shutting down
                
            }
            catch
            {
                throw;
            }
//            finally
//            {
//                if (SatellitesToDraw != null)
//                    SatellitesToDraw.Dispose();
//                if (SatellitesToRender != null)
//                    SatellitesToRender.Dispose();
//            }
        }

		private Color GetFillColor(SignalToNoiseRatio signal)
		{
			if (signal.Value < 10)
				return pFillNone[signal.Value];
			else if (signal.Value < 20)
				return pFillPoor[signal.Value - 10];
			else if (signal.Value < 30)
				return pFillModerate[signal.Value - 20];
			else if (signal.Value < 40)
				return pFillGood[signal.Value - 30];
			else if (signal.Value < 50)
				return pFillExcellent[signal.Value - 40];
			else
				return pFillExcellent[9];
		}

		private Color GetOutlineColor(SignalToNoiseRatio signal)
		{
			if (signal.Value < 10)
				return pOutlineNone[signal.Value];
			else if (signal.Value < 20)
				return pOutlinePoor[signal.Value - 10];
			else if (signal.Value < 30)
				return pOutlineModerate[signal.Value - 20];
			else if (signal.Value < 40)
				return pOutlineGood[signal.Value - 30];
			else if (signal.Value < 50)
				return pOutlineExcellent[signal.Value - 40];
			else
				return pOutlineExcellent[9];
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "Transparent")]
		[Description("Controls the color inside of satellite icons with no signal.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color NoSignalFillColor
		{
			get
			{
				return pSatelliteNoSignalFillColor;
			}
			set
			{
				if (pSatelliteNoSignalFillColor.Equals(value)) return;
				pSatelliteNoSignalFillColor = value;
				pFillNone.StartColor = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "Red")]
		[Description("Controls the color inside of satellite icons with a weak signal.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color PoorSignalFillColor
		{
			get
			{
				return pSatellitePoorSignalFillColor;
			}
			set
			{
				if (pSatellitePoorSignalFillColor.Equals(value)) return;
				pSatellitePoorSignalFillColor = value;
				pFillNone.EndColor = value;
				pFillPoor.StartColor = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "Orange")]
		[Description("Controls the color inside of satellite icons with a moderate signal.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color ModerateSignalFillColor
		{
			get
			{
				return pSatelliteModerateSignalFillColor;
			}
			set
			{
				if (pSatelliteModerateSignalFillColor.Equals(value)) return;
				pSatelliteModerateSignalFillColor = value;
				pFillModerate.StartColor = value;
				pFillPoor.EndColor = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "Green")]
		[Description("Controls the color inside of satellite icons with a strong signal.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color GoodSignalFillColor
		{
			get
			{
				return pSatelliteGoodSignalFillColor;
			}
			set
			{
				if (pSatelliteGoodSignalFillColor.Equals(value)) return;
				pSatelliteGoodSignalFillColor = value;
				pFillGood.StartColor = value;
				pFillModerate.EndColor = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "LightGreen")]
		[Description("Controls the color inside of satellite icons with a very strong signal.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color ExcellentSignalFillColor
		{
			get
			{
				return pSatelliteExcellentSignalFillColor;
			}
			set
			{
				if (pSatelliteExcellentSignalFillColor.Equals(value)) return;
				pSatelliteExcellentSignalFillColor = value;
				pFillExcellent.EndColor = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "Transparent")]
		[Description("Controls the color around satellite icons with no signal.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color NoSignalOutlineColor
		{
			get
			{
				return pSatelliteNoSignalOutlineColor;
			}
			set
			{
				if (pSatelliteNoSignalOutlineColor.Equals(value)) return;
				pSatelliteNoSignalOutlineColor = value;
				pOutlineNone.StartColor = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "Black")]
		[Description("Controls the color around satellite icons with a weak signal.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color PoorSignalOutlineColor
		{
			get
			{
				return pSatellitePoorSignalOutlineColor;
			}
			set
			{
				if (pSatellitePoorSignalOutlineColor.Equals(value)) return;
				pSatellitePoorSignalOutlineColor = value;
				pOutlineNone.EndColor = value;
				pOutlinePoor.StartColor = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "Black")]
		[Description("Controls the color around satellite icons with a moderate signal.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color ModerateSignalOutlineColor
		{
			get
			{
				return pSatelliteModerateSignalOutlineColor;
			}
			set
			{
				if (pSatelliteModerateSignalOutlineColor.Equals(value)) return;
				pSatelliteModerateSignalOutlineColor = value;
				pOutlinePoor.EndColor = value;
				pOutlineModerate.StartColor = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "Black")]
		[Description("Controls the color around satellite icons with a strong signal.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color GoodSignalOutlineColor
		{
			get
			{
				return pSatelliteGoodSignalOutlineColor;
			}
			set
			{
				if (pSatelliteGoodSignalOutlineColor.Equals(value)) return;
				pSatelliteGoodSignalOutlineColor = value;
				pOutlineModerate.EndColor = value;
				pOutlineGood.StartColor = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "Black")]
		[Description("Controls the color around satellite icons with a very strong signal.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color ExcellentSignalOutlineColor
		{
			get
			{
				return pSatelliteExcellentSignalOutlineColor;
			}
			set
			{
				if (pSatelliteExcellentSignalOutlineColor.Equals(value)) return;
				pSatelliteExcellentSignalOutlineColor = value;
				pOutlineExcellent.StartColor = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "LimeGreen")]
		[Description("Controls the color of the ellipse drawn around fixed satellites.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color FixColor
		{
			get
			{
#if PocketPC
				return pSatelliteFixBrush.Color;
#else
                return pSatelliteFixColor;
#endif
			}
			set
			{
#if PocketPC
				if(pSatelliteFixBrush.Color.Equals(value))
					return;
				pSatelliteFixBrush.Color = value;
#else
                if (pSatelliteFixColor.Equals(value)) return;
                pSatelliteFixColor = value;
#endif
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Behavior")]
		[DefaultValue(typeof(bool), "True")]
		[Description("Controls whether the Satellites property is set manually, or automatically read from any available GPS device.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public bool IsUsingRealTimeData
		{
			get
			{
				return pIsUsingRealTimeData;
			}
			set
			{
				if (pIsUsingRealTimeData == value) return;
				pIsUsingRealTimeData = value;
#if !DesignTime
				if (pIsUsingRealTimeData)
					pSatellites.MergeWith(GeoFramework.IO.Devices.CurrentSatellites);
#endif
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Font), "Tahoma, 6pt")]
		[Description("Controls the font used to draw the strength of each satellite.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Font SignalStrengthLabelFont
		{
			get
			{
				return pSignalStrengthLabelFont;
			}
			set
			{
				if (pSignalStrengthLabelFont.Equals(value)) return;
				pSignalStrengthLabelFont = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "Black")]
		[Description("Controls the color used to draw the strength of each satellite.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color SignalStrengthLabelColor
		{
			get
			{
				return pSignalStrengthLabelBrush.Color;
			}
			set
			{
				if (pSignalStrengthLabelBrush.Color.Equals(value)) return;
				pSignalStrengthLabelBrush.Color = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Font), "Tahoma, 8pt")]
		[Description("Controls the font used to draw the ID of each satellite.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Font PseudorandomNumberFont
		{
			get
			{
				return pPseudorandomNumberFont;
			}
			set
			{
				if (pPseudorandomNumberFont.Equals(value)) return;
				pPseudorandomNumberFont = value;
				InvokePaintOffScreen();
			}
		}

#if !PocketPC || DesignTime
		[Category("Satellite Colors")]
		[DefaultValue(typeof(Color), "Black")]
		[Description("Controls the color used to draw the ID of each satellite.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		[EditorBrowsable(EditorBrowsableState.Always)]
#endif
		public Color PseudorandomNumberColor
		{
			get
			{
				return pPseudorandomNumberBrush.Color;
			}
			set
			{
				if (pPseudorandomNumberBrush.Color.Equals(value)) return;
				pPseudorandomNumberBrush.Color = value;
				InvokePaintOffScreen();
			}
		}

		private void Devices_CurrentSatellitesChanged(object sender, SatelliteCollectionEventArgs e)
		{
#if !DesignTime
			if (pIsUsingRealTimeData)
			{
				lock(pSatellites.SyncRoot)
				{
					if(pSatellites.MergeWith(e.SatelliteCollection))
						BeginInvokePaintOffScreen();
				}
			}
#endif
		}
	}

    //class FourColorPanel : Panel
    //{

    //    private Color topTopColor;
    //    private Color topBottomColor;
    //    private Color bottomTopColor;
    //    private Color bottomBottomColor;

    //    public FourColorPanel()
    //        : base()
    //    {
    //        SetBackgroundColors(BackColor.GetHue());
    //    }

    //    public override System.Drawing.Color BackColor
    //    {
    //        get
    //        {
    //            return base.BackColor;
    //        }
    //        set
    //        {
    //            base.BackColor = value;
    //            SetBackgroundColors(value.GetHue());
    //        }
    //    }

    //    private void SetBackgroundColors(float baseHue)
    //    {
    //        topTopColor = ColorConversions.ColorFromAhsb(255, baseHue,
    //            0.2958f, 0.7292f);
    //        topBottomColor = ColorConversions.ColorFromAhsb(255, baseHue,
    //            0.5875f, 0.35f);
    //        bottomTopColor = ColorConversions.ColorFromAhsb(255, baseHue,
    //            0.7458f, 0.2f);
    //        bottomBottomColor = ColorConversions.ColorFromAhsb(255, baseHue,
    //            0.6f, 0.4042f);
    //    }

    //    protected override void OnPaint(PaintEventArgs e)
    //    {
    //        Rectangle topRect = new Rectangle(0, 0, ClientRectangle.Width,
    //            ClientRectangle.Height / 2);
    //        Rectangle bottomRect = new Rectangle(0, topRect.Height,
    //            ClientRectangle.Width,
    //            ClientRectangle.Height - topRect.Height - 1);
    //        using (Brush topBrush = new LinearGradientBrush(topRect,
    //            topTopColor, topBottomColor, LinearGradientMode.Vertical))
    //        {
    //            e.Graphics.FillRectangle(topBrush, topRect);
    //        }
    //        using (Brush bottomBrush = new LinearGradientBrush(bottomRect,
    //            bottomTopColor, bottomBottomColor,
    //            LinearGradientMode.Vertical))
    //        {
    //            e.Graphics.FillRectangle(bottomBrush, bottomRect);
    //        }
    //    }

    


}
